<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>作用域</title>
</head>
<body>
<!--
作用域:
    概念: 规定了变量能够被访问的"范围"，离开了这个"范围"变量便不能被访问
    分类:
        （1）局部作用域
            1.函数作用域: 在函数内部声明的变量只能在函数内部被访问，外部无法直接访问
            2.块作用域: 在函数内部用{}包裹的代码称为代码块，代码块内部声明的变量外部将【有可能】无法被访问
                       用let声明的变量外部不能被访问，用var声明的变量外部可以被访问————var有bug
        （2）全局作用域
            <script>标签或者.js文件最外层就是全局作用域，在此生命的变量在函数内部也可以访问
            （全局作用域中生命的变量，在任何其他作用域都能访问）
            作用域链: 作用域链本质上是底层的变量查找机制
                    在函数执行时，会优先在当前函数作用域中查找变量，如果当前作用域查不到则会依次逐级查找父级作用域直到全局作用域
                    (子级作用域能够访问父作用域，父级作用域无法访问子级作用域)
        （3）垃圾回收机制
            内存的生命周期:
                1.内存分配: 当我们声明变量、函数、对象的时候，系统会自动的为他们分配内存
                2.内存使用: 即读写内存，也就是使用变量、函数等
                3.内存回收: 使用完毕，由垃圾回收器自动回收不再使用的内存
            说明:
                全局变量一般不会回收————关闭页面时才会回收
                局部变量的值只要不用了就会被自动回收掉
            内存泄露:
                程序中分配的内存由于某种原因程序未释放或者无法释放就叫做内存泄漏

        （4）闭包
            概念：一个函数对周围状态的引用捆绑在一起，内层函数中访问到其他外层函数的作用域
            简单理解：闭包 = 内层函数 + 外层函数的变量
            作用：
                封闭数据、提供操作，外部也可以访问函数内部的变量
            基本格式：
                外部可以是使用函数内部的变量
                    1.声明一个闭包
                    // 闭包名
                     function outer() {
                        // 闭包属性
                        const a = 10
                        // 闭包方法
                        function fn() {
                            console.log(a)
                        }
                        return fn
                        // 里层函数的整体 + 外层函数的 const a = 1 是一个闭包
                    }
                    2.使用一个闭包
                    // 声明调用函数
                    const fun = outer()
                    // 开始调用函数
                    fun()
           应用：实现数据的私有

        （5）变量提升
            var声明的变量允许变量在被定义之前使用
         (6) 函数提升
             1. JS会把所有函数声明提升到当前作用域的最前面
                只提升函数声明，不提升函数调用
                fn()
                function fn() {
                    console.log('函数提升')
                }

            2. 函数表达式必须先声明赋值后调用
                fn1()
                var fn1 = function () {
                    console.log('函数表达式不存在提升的现象...')
                }

-->
</body>
<script>
    // 声明一个闭包outer
    function outer() {
        // 闭包中声明的属性
        const a = 10
        // 闭包中声明的方法
        function fn() {
            console.log(a)
        }
        return fn
        // 里层函数的整体 + 外层函数的 const a = 1 是一个闭包
    }

    // 使用一个闭包
    const fun = outer()
    fun() // 调用函数

    fn()
    function fn() {
        console.log('函数提升')
    }

    fn1()
    var fn1 = function () {
        console.log('函数表达式不存在提升的现象...')
    }

</script>
</html>